home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / cvs-1_3.lha / cvs-1.3 / src / recurse.c < prev    next >
C/C++ Source or Header  |  1992-04-09  |  13KB  |  536 lines

  1. /*
  2.  * Copyright (c) 1992, Brian Berliner and Jeff Polk
  3.  * 
  4.  * You may distribute under the terms of the GNU General Public License as
  5.  * specified in the README file that comes with the CVS 1.3 kit.
  6.  * 
  7.  * General recursion handler
  8.  * 
  9.  */
  10.  
  11. #include "cvs.h"
  12.  
  13. #ifndef lint
  14. static char rcsid[] = "@(#)recurse.c 1.22 92/04/10";
  15. #endif
  16.  
  17. #if __STDC__
  18. static int do_dir_proc (Node * p);
  19. static int do_file_proc (Node * p);
  20. static void addlist (List ** listp, char *key);
  21. #else
  22. static int do_file_proc ();
  23. static int do_dir_proc ();
  24. static void addlist ();
  25. #endif                /* __STDC__ */
  26.  
  27.  
  28. /*
  29.  * Local static versions eliminates the need for globals
  30.  */
  31. static int (*fileproc) ();
  32. static int (*filesdoneproc) ();
  33. static Dtype (*direntproc) ();
  34. static int (*dirleaveproc) ();
  35. static int which;
  36. static Dtype flags;
  37. static int aflag;
  38. static int readlock;
  39. static int dosrcs;
  40. static char update_dir[PATH_MAX];
  41. static char *repository = NULL;
  42. static List *entries = NULL;
  43. static List *srcfiles = NULL;
  44. static List *filelist = NULL;
  45. static List *dirlist = NULL;
  46.  
  47. /*
  48.  * Called to start a recursive command Command line arguments are processed
  49.  * if present, otherwise the local directory is processed.
  50.  */
  51. int
  52. start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc,
  53.          argc, argv, local, which, aflag, readlock,
  54.          update_preload, dosrcs)
  55.     int (*fileproc) ();
  56.     int (*filesdoneproc) ();
  57.     Dtype (*direntproc) ();
  58.     int (*dirleaveproc) ();
  59.     int argc;
  60.     char *argv[];
  61.     int local;
  62.     int which;
  63.     int aflag;
  64.     int readlock;
  65.     char *update_preload;
  66.     int dosrcs;
  67. {
  68.     int i, err = 0;
  69.     Dtype flags;
  70.  
  71.     if (update_preload == NULL)
  72.     update_dir[0] = '\0';
  73.     else
  74.     (void) strcpy (update_dir, update_preload);
  75.  
  76.     if (local)
  77.     flags = R_SKIP_DIRS;
  78.     else
  79.     flags = R_PROCESS;
  80.  
  81.     /* clean up from any previous calls to start_recursion */
  82.     if (repository)
  83.     {
  84.     free (repository);
  85.     repository = (char *) NULL;
  86.     }
  87.     if (entries)
  88.     dellist (&entries);
  89.     if (srcfiles)
  90.     dellist (&srcfiles);
  91.     if (filelist)
  92.     dellist (&filelist);
  93.     if (dirlist)
  94.     dellist (&dirlist);
  95.  
  96.     if (argc == 0)
  97.     {
  98.  
  99.     /*
  100.      * There were no arguments, so we'll probably just recurse. The
  101.      * exception to the rule is when we are called from a directory
  102.      * without any CVS administration files.  That has always meant to
  103.      * process each of the sub-directories, so we pretend like we were
  104.      * called with the list of sub-dirs of the current dir as args
  105.      */
  106.     if ((which & W_LOCAL) && !isdir (CVSADM) && !isdir (OCVSADM))
  107.         dirlist = Find_Dirs ((char *) NULL, W_LOCAL);
  108.     else
  109.         addlist (&dirlist, ".");
  110.  
  111.     err += do_recursion (fileproc, filesdoneproc, direntproc,
  112.                 dirleaveproc, flags, which, aflag,
  113.                 readlock, dosrcs);
  114.     }
  115.     else
  116.     {
  117.  
  118.     /*
  119.      * There were arguments, so we have to handle them by hand. To do
  120.      * that, we set up the filelist and dirlist with the arguments and
  121.      * call do_recursion.  do_recursion recognizes the fact that the
  122.      * lists are non-null when it starts and doesn't update them
  123.      */
  124.  
  125.     /* look for args with /-s in them */
  126.     for (i = 0; i < argc; i++)
  127.         if (index (argv[i], '/') != NULL)
  128.         break;
  129.  
  130.     /* if we didn't find any hard one's, do it the easy way */
  131.     if (i == argc)
  132.     {
  133.         /* set up the lists */
  134.         for (i = 0; i < argc; i++)
  135.         {
  136.         if (isdir (argv[i]))
  137.             addlist (&dirlist, argv[i]);
  138.         else
  139.         {
  140.             if (isdir (CVSADM) || isdir (OCVSADM))
  141.             {
  142.             char *repos;
  143.             char tmp[PATH_MAX];
  144.  
  145.             repos = Name_Repository ((char *) NULL, update_dir);
  146.             (void) sprintf (tmp, "%s/%s", repos, argv[i]);
  147.             if (isdir (tmp))
  148.                 addlist (&dirlist, argv[i]);
  149.             else
  150.                 addlist (&filelist, argv[i]);
  151.             free (repos);
  152.             }
  153.             else
  154.             addlist (&filelist, argv[i]);
  155.         }
  156.         }
  157.  
  158.         /* we aren't recursive if no directories were specified */
  159.         if (dirlist == NULL)
  160.         local = 1;
  161.  
  162.         /* process the lists */
  163.         err += do_recursion (fileproc, filesdoneproc, direntproc,
  164.                 dirleaveproc, flags, which, aflag,
  165.                 readlock, dosrcs);
  166.     }
  167.     /* otherwise - do it the hard way */
  168.     else
  169.     {
  170.         char *cp;
  171.         char *dir = (char *) NULL;
  172.         char *comp = (char *) NULL;
  173.         char *oldupdate = (char *) NULL;
  174.         char savewd[PATH_MAX];
  175.  
  176.         if (getwd (savewd) == NULL)
  177.         error (1, 0, "could not get working directory: %s", savewd);
  178.  
  179.         for (i = 0; i < argc; i++)
  180.         {
  181.         /* split the arg into the dir and component parts */
  182.         dir = xstrdup (argv[i]);
  183.         if ((cp = rindex (dir, '/')) != NULL)
  184.         {
  185.             *cp = '\0';
  186.             comp = xstrdup (cp + 1);
  187.             oldupdate = xstrdup (update_dir);
  188.             if (update_dir[0] != '\0')
  189.             (void) strcat (update_dir, "/");
  190.             (void) strcat (update_dir, dir);
  191.         }
  192.         else
  193.         {
  194.             comp = xstrdup (dir);
  195.             if (dir)
  196.             free (dir);
  197.             dir = (char *) NULL;
  198.         }
  199.  
  200.         /* chdir to the appropriate place if necessary */
  201.         if (dir && chdir (dir) < 0)
  202.             error (1, errno, "could not chdir to %s", dir);
  203.  
  204.         /* set up the list */
  205.         if (isdir (comp))
  206.             addlist (&dirlist, comp);
  207.         else
  208.         {
  209.             if (isdir (CVSADM) || isdir (OCVSADM))
  210.             {
  211.             char *repos;
  212.             char tmp[PATH_MAX];
  213.  
  214.             repos = Name_Repository ((char *) NULL, update_dir);
  215.             (void) sprintf (tmp, "%s/%s", repos, comp);
  216.             if (isdir (tmp))
  217.                 addlist (&dirlist, comp);
  218.             else
  219.                 addlist (&filelist, comp);
  220.             free (repos);
  221.             }
  222.             else
  223.             addlist (&filelist, comp);
  224.         }
  225.  
  226.         /* do the recursion */
  227.         err += do_recursion (fileproc, filesdoneproc, direntproc,
  228.                     dirleaveproc, flags, which,
  229.                     aflag, readlock, dosrcs);
  230.  
  231.         /* chdir back and fix update_dir if necessary */
  232.         if (dir && chdir (savewd) < 0)
  233.             error (1, errno, "could not chdir to %s", dir);
  234.         if (oldupdate)
  235.         {
  236.             (void) strcpy (update_dir, oldupdate);
  237.             free (oldupdate);
  238.         }
  239.  
  240.         }
  241.         if (dir)
  242.         free (dir);
  243.         if (comp)
  244.         free (comp);
  245.     }
  246.     }
  247.     return (err);
  248. }
  249.  
  250. /*
  251.  * Implement the recursive policies on the local directory.  This may be
  252.  * called directly, or may be called by start_recursion
  253.  */
  254. int
  255. do_recursion (xfileproc, xfilesdoneproc, xdirentproc, xdirleaveproc,
  256.           xflags, xwhich, xaflag, xreadlock, xdosrcs)
  257.     int (*xfileproc) ();
  258.     int (*xfilesdoneproc) ();
  259.     Dtype (*xdirentproc) ();
  260.     int (*xdirleaveproc) ();
  261.     Dtype xflags;
  262.     int xwhich;
  263.     int xaflag;
  264.     int xreadlock;
  265.     int xdosrcs;
  266. {
  267.     int err = 0;
  268.     int dodoneproc = 1;
  269.     char *srepository;
  270.  
  271.     /* do nothing if told */
  272.     if (xflags == R_SKIP_ALL)
  273.     return (0);
  274.  
  275.     /* set up the static vars */
  276.     fileproc = xfileproc;
  277.     filesdoneproc = xfilesdoneproc;
  278.     direntproc = xdirentproc;
  279.     dirleaveproc = xdirleaveproc;
  280.     flags = xflags;
  281.     which = xwhich;
  282.     aflag = xaflag;
  283.     readlock = noexec ? 0 : xreadlock;
  284.     dosrcs = xdosrcs;
  285.  
  286.     /*
  287.      * Fill in repository with the current repository
  288.      */
  289.     if (which & W_LOCAL)
  290.     {
  291.     if (isdir (CVSADM) || isdir (OCVSADM))
  292.         repository = Name_Repository ((char *) NULL, update_dir);
  293.     else
  294.         repository = NULL;
  295.     }
  296.     else
  297.     {
  298.     repository = xmalloc (PATH_MAX);
  299.     (void) getwd (repository);
  300.     }
  301.     srepository = repository;        /* remember what to free */
  302.  
  303.     /*
  304.      * The filesdoneproc needs to be called for each directory where files
  305.      * processed, or each directory that is processed by a call where no
  306.      * directories were passed in.  In fact, the only time we don't want to
  307.      * call back the filesdoneproc is when we are processing directories that
  308.      * were passed in on the command line (or in the special case of `.' when
  309.      * we were called with no args
  310.      */
  311.     if (dirlist != NULL && filelist == NULL)
  312.     dodoneproc = 0;
  313.  
  314.     /*
  315.      * If filelist or dirlist is already set, we don't look again. Otherwise,
  316.      * find the files and directories
  317.      */
  318.     if (filelist == NULL && dirlist == NULL)
  319.     {
  320.     /* both lists were NULL, so start from scratch */
  321.     if (fileproc != NULL && flags != R_SKIP_FILES)
  322.     {
  323.         int lwhich = which;
  324.  
  325.         /* be sure to look in the attic if we have sticky tags/date */
  326.         if ((lwhich & W_ATTIC) == 0)
  327.         if (isreadable (CVSADM_TAG))
  328.             lwhich |= W_ATTIC;
  329.  
  330.         /* find the files and fill in entries if appropriate */
  331.         filelist = Find_Names (repository, lwhich, aflag, &entries);
  332.     }
  333.  
  334.     /* find sub-directories if we will recurse */
  335.     if (flags != R_SKIP_DIRS)
  336.         dirlist = Find_Dirs (repository, which);
  337.     }
  338.     else
  339.     {
  340.     /* something was passed on the command line */
  341.     if (filelist != NULL && fileproc != NULL)
  342.     {
  343.         /* we will process files, so pre-parse entries */
  344.         if (which & W_LOCAL)
  345.         entries = ParseEntries (aflag);
  346.     }
  347.     }
  348.  
  349.     /* process the files (if any) */
  350.     if (filelist != NULL)
  351.     {
  352.     /* read lock it if necessary */
  353.     if (readlock && repository && Reader_Lock (repository) != 0)
  354.         error (1, 0, "read lock failed - giving up");
  355.  
  356.     /* pre-parse the source files */
  357.     if (dosrcs && repository)
  358.         srcfiles = RCS_parsefiles (filelist, repository);
  359.     else
  360.         srcfiles = (List *) NULL;
  361.  
  362.     /* process the files */
  363.     err += walklist (filelist, do_file_proc);
  364.  
  365.     /* unlock it */
  366.     if (readlock)
  367.         Lock_Cleanup ();
  368.  
  369.     /* clean up */
  370.     dellist (&filelist);
  371.     dellist (&srcfiles);
  372.     dellist (&entries);
  373.     }
  374.  
  375.     /* call-back files done proc (if any) */
  376.     if (dodoneproc && filesdoneproc != NULL)
  377.     err = filesdoneproc (err, repository, update_dir[0] ? update_dir : ".");
  378.  
  379.     /* process the directories (if necessary) */
  380.     if (dirlist != NULL)
  381.     err += walklist (dirlist, do_dir_proc);
  382. #ifdef notdef
  383.     else if (dirleaveproc != NULL)
  384.     err += dirleaveproc(".", err, ".");
  385. #endif
  386.     dellist (&dirlist);
  387.  
  388.     /* free the saved copy of the pointer if necessary */
  389.     if (srepository)
  390.     {
  391.     (void) free (srepository);
  392.     repository = (char *) NULL;
  393.     }
  394.  
  395.     return (err);
  396. }
  397.  
  398. /*
  399.  * Process each of the files in the list with the callback proc
  400.  */
  401. static int
  402. do_file_proc (p)
  403.     Node *p;
  404. {
  405.     if (fileproc != NULL)
  406.     return (fileproc (p->key, update_dir, repository, entries, srcfiles));
  407.     else
  408.     return (0);
  409. }
  410.  
  411. /*
  412.  * Process each of the directories in the list (recursing as we go)
  413.  */
  414. static int
  415. do_dir_proc (p)
  416.     Node *p;
  417. {
  418.     char *dir = p->key;
  419.     char savewd[PATH_MAX];
  420.     char newrepos[PATH_MAX];
  421.     List *sdirlist;
  422.     char *srepository;
  423.     char *cp;
  424.     Dtype dir_return = R_PROCESS;
  425.     int stripped_dot = 0;
  426.     int err = 0;
  427.  
  428.     /* set up update_dir - skip dots if not at start */
  429.     if (strcmp (dir, ".") != 0)
  430.     {
  431.     if (update_dir[0] != '\0')
  432.     {
  433.         (void) strcat (update_dir, "/");
  434.         (void) strcat (update_dir, dir);
  435.     }
  436.     else
  437.         (void) strcpy (update_dir, dir);
  438.  
  439.     /*
  440.      * Here we need a plausible repository name for the sub-directory. We
  441.      * create one by concatenating the new directory name onto the
  442.      * previous repository name.  The only case where the name should be
  443.      * used is in the case where we are creating a new sub-directory for
  444.      * update -d and in that case the generated name will be correct.
  445.      */
  446.     if (repository == NULL)
  447.         newrepos[0] = '\0';
  448.     else
  449.         (void) sprintf (newrepos, "%s/%s", repository, dir);
  450.     }
  451.     else
  452.     {
  453.     if (update_dir[0] == '\0')
  454.         (void) strcpy (update_dir, dir);
  455.  
  456.     if (repository == NULL)
  457.         newrepos[0] = '\0';
  458.     else
  459.         (void) strcpy (newrepos, repository);
  460.     }
  461.  
  462.     /* call-back dir entry proc (if any) */
  463.     if (direntproc != NULL)
  464.     dir_return = direntproc (dir, newrepos, update_dir);
  465.  
  466.     /* only process the dir if the return code was 0 */
  467.     if (dir_return != R_SKIP_ALL)
  468.     {
  469.     /* save our current directory and static vars */
  470.     if (getwd (savewd) == NULL)
  471.         error (1, 0, "could not get working directory: %s", savewd);
  472.     sdirlist = dirlist;
  473.     srepository = repository;
  474.     dirlist = NULL;
  475.  
  476.     /* cd to the sub-directory */
  477.     if (chdir (dir) < 0)
  478.         error (1, errno, "could not chdir to %s", dir);
  479.  
  480.     /* honor the global SKIP_DIRS (a.k.a. local) */
  481.     if (flags == R_SKIP_DIRS)
  482.         dir_return = R_SKIP_DIRS;
  483.  
  484.     /* remember if the `.' will be stripped for subsequent dirs */
  485.     if (strcmp (update_dir, ".") == 0)
  486.     {
  487.         update_dir[0] = '\0';
  488.         stripped_dot = 1;
  489.     }
  490.  
  491.     /* make the recursive call */
  492.     err += do_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc,
  493.                 dir_return, which, aflag, readlock, dosrcs);
  494.  
  495.     /* put the `.' back if necessary */
  496.     if (stripped_dot)
  497.         (void) strcpy (update_dir, ".");
  498.  
  499.     /* call-back dir leave proc (if any) */
  500.     if (dirleaveproc != NULL)
  501.         err = dirleaveproc (dir, err, update_dir);
  502.  
  503.     /* get back to where we started and restore state vars */
  504.     if (chdir (savewd) < 0)
  505.         error (1, errno, "could not chdir to %s", savewd);
  506.     dirlist = sdirlist;
  507.     repository = srepository;
  508.     }
  509.  
  510.     /* put back update_dir */
  511.     if ((cp = rindex (update_dir, '/')) != NULL)
  512.     *cp = '\0';
  513.     else
  514.     update_dir[0] = '\0';
  515.  
  516.     return (err);
  517. }
  518.  
  519. /*
  520.  * Add a node to a list allocating the list if necessary
  521.  */
  522. static void
  523. addlist (listp, key)
  524.     List **listp;
  525.     char *key;
  526. {
  527.     Node *p;
  528.  
  529.     if (*listp == NULL)
  530.     *listp = getlist ();
  531.     p = getnode ();
  532.     p->type = FILES;
  533.     p->key = xstrdup (key);
  534.     (void) addnode (*listp, p);
  535. }
  536.